using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace BridgeUI
{
    /// <summary>
    /// 这是游戏的主类型
    /// </summary>
    public partial class BrApp : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        internal SpriteBatch Sprite { get { return spriteBatch; } }

        public BrApp()
        {
            WPApp.UnhandledException += WPApp_UnhandledException;

            graphics = new GraphicsDeviceManager(this);
            //Content.RootDirectory = "Content"; 不能使用 Game 自带的Content，以避免和用户冲突
            // 在 reflector 的数据中，表明，我们可以自己建一个ContentManeger，并且不与系统冲突

            BrContent = new ContentManager(Services) {RootDirectory = @"Bridge\Content"};
        }

        internal ContentManager BrContent { get; private set; }
        public World World { get; private set; }
        public Application WPApp { get { return Application.Current; } }

        /// <summary>
        /// User could do something, before everything begin.
        /// </summary>
        protected virtual void Prepare() { }
        protected virtual void LoadComponent() { }
        protected virtual void ComponentLoaded() { }
        private void MyPrepare()
        {
            State.Preparing();
            Console = new Console(this);
            World = new World(this);
            State.Initing();
        }
        private void MyInit()
        {
            World.Init();
            State.Inited();
        }
        private void MyComponentLoaded()
        {

        }

        /// <summary>
        /// 允许游戏在开始运行之前执行其所需的任何初始化。
        /// 游戏能够在此时查询任何所需服务并加载任何非图形
        /// 相关的内容。调用 base.Initialize 将枚举所有组件
        /// 并对其进行初始化。 
        /// </summary>
        protected sealed override void Initialize()
        {
            Prepare();
            MyPrepare();
            base.Initialize();
            MyInit();
            LoadComponent();
        }

        protected sealed override void BeginRun()
        {
            State.StartLoadComponent();
            MyComponentLoaded();
            ComponentLoaded();
            State.ComponentLoaded();
            base.BeginRun(); // in fact is empty.
            State.StartRun();
        }
        protected sealed override void EndRun()
        {
            base.EndRun();
        }

        /// <summary>
        /// 对于每个游戏会调用一次 LoadContent，
        /// 用于加载所有内容。
        /// </summary>
        protected override void LoadContent()
        {
            State.LoadContenting();
            spriteBatch = new SpriteBatch(GraphicsDevice);
            Console.LoadContent();
            State.LoadContented();
        }

        /// <summary>
        /// 对于每个游戏会调用一次 UnloadContent，
        /// 用于取消加载所有内容。
        /// </summary>
        protected override void UnloadContent()
        {
            BrContent.Unload(); // 由反编译信息，实际上Game内部先 this.content.Unload(); 然后Unload()
            // TODO: 在此处取消加载任何非 ContentManager 内容
        }

        /// <summary>
        /// 允许游戏运行逻辑，例如更新全部内容、
        /// 检查冲突、收集输入信息以及播放音频。
        /// </summary>
        /// <param name="gameTime">提供计时值的快照。</param>
        protected sealed override void Update(GameTime gameTime)
        {
            // 允许游戏退出
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            World.Update(gameTime);
            base.Update(gameTime);
        }

        protected sealed override bool BeginDraw()
        {
            return base.BeginDraw();
        }
        /// <summary>
        /// 当游戏该进行自我绘制时调用此项。
        /// </summary>
        /// <param name="gameTime">提供计时值的快照。</param>
        protected sealed override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(World.BackGround);
            Console.Draw();
            World.Draw(gameTime);
            base.Draw(gameTime);
        }
        protected sealed override void EndDraw()
        {
            base.EndDraw();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                State.Exiting();
            }
 	        base.Dispose(disposing);
            if (disposing)
            {
                State.Exited();
            }
        }

        void WPApp_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // An unhandled exception has occurred; break into the debugger
                MessageBox.Show(e.ExceptionObject.ToString());
                var mess = e.ExceptionObject.ToString();
                System.Diagnostics.Debugger.Log(2, e.ExceptionObject.Message, e.ExceptionObject.ToString());
                System.Diagnostics.Debugger.Break();
            }
            else
            {
                // TODO: report exception to developer
                Exit();
            }
        }

        public StateStruct State { get; private set; }
        public struct StateStruct
        {
            StateStruct(short state)
            {
                this.state = state;
            }
            private short state;   /* @1,0=00: UnPrepared ,@0=1: Preparing or prepared
                                    * @1=1: Initing or inited, prepared.
                                    * @2=1: inited.
                                    * @3=1: Runing. 0: NotRuning
                                    * @4=1: Exiting, Runing stoped.
                                    * @5=1: Exited, Bridge Connect Break.
                                    * 
                                    * @9=1: Pausing.
                                    * @8=0: ContentNotLoaded, @8=1:ContentLoading, @9=1: ContentLoaded, avaliable
                                    * @10=0: ContentUnLoading, @11 = 1, ContentUnloaded
                                    * 
                                    * @12=1: ComponentLoading
                                    * @13=1: ComponentLoaded, avaliable
                                    */

            public bool IsPreparing { get { return state.AtBit(0) && !state.AtBit(1); } }
            public bool IsPrepared { get { return state.AtBit(1); } }
            public bool IsIniting { get { return state.AtBit(1) && !state.AtBit(2); } }
            public bool IsInited { get { return state.AtBit(2); } }
            public bool IsRuning { get { return state.AtBit(3); } }
            public bool IsPause { get { return state.AtBit(8); } }
            public bool IsExiting { get { return state.AtBit(4); } }
            public bool IsExited { get { return state.AtBit(5); } }
            public bool IsContentNotLoaded { get { return (state & (15<<8)) == 0; } }
            public bool IsContentLoading { get { return state.AtBit(8); } }
            public bool IsContentLoaded { get { return state.AtBit(9); } }
            public bool IsContentUnLoading { get { return state.AtBit(10); } }
            public bool IsContentUnLoaded { get { return state.AtBit(11); } }
            public bool ContentAvaliable { get { return IsContentLoaded; } }
            public bool BridgeAvaliable { get { return IsInited; } }
            public bool IsComponentLoading { get { return state.AtBit(12); } }
            public bool IsComponentLoaded { get { return state.AtBit(13); } }
            public bool ComponentAvaliable { get { return IsComponentLoaded; } }

            private const int UnState = 0;
            private const int PreparingState = 1;
            private const int InitingState = 3;
            private const int InitedState = 7;
            private const int StartRunState = 15;
            
            internal void Preparing()
            {
                state = state.SetBit(1);
            }
            internal void Initing()
            {
                state |= 3;
            }
            internal void Inited()
            {
                state |= InitedState;
            }
            internal void StartRun()
            {
                state |= StartRunState;
            }
            internal void LoadContenting()
            {
                state |= (1 << 8);
            }
            internal void LoadContented()
            {
                state = (short)((state & (~(3 << 8))) | (2 << 8));
            }
            internal void ContentLoaded()
            {
                state = state.SetBit(10).ClrBit(9);
            }
            internal void ContentUnLoaded()
            {
                state = state.SetBit(11).ClrBit(10);
            }
            internal void Exiting()
            {
                state = state.SetBit(4).ClrBit(3);
            }
            internal void Exited()
            {
                state = state.SetBit(5).ClrBit(4);
            }
            internal void Pause()
            {
                state = state.SetBit(9);
            }
            internal void Resume()
            {
                state = state.ClrBit(9);
            }
            internal void StartLoadComponent()
            {
                state = state.SetBit(12);
            }

            internal void ComponentLoaded()
            {
                state = state.SetBit(13).ClrBit(12);
            }
        }
    }
}
